package com.box2dwrapper.view
{
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.Joints.b2Joint;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;
	
	import com.box2dwrapper.manager.DragManager;
	import com.box2dwrapper.object.AbstractObject;
	import com.box2dwrapper.object.Box;
	import com.box2dwrapper.object.Circle;
	import com.box2dwrapper.object.Joint;
	import com.box2dwrapper.object.OrientedBox;
	import com.box2dwrapper.view.core.AbstractView;
	import com.box2dwrapper.view.core.IView;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;

	public class Box2DView extends AbstractView implements IView
	{
		public function Box2DView(numWorldWidth:Number = 2000, numWorldHeight:Number = 2000, numHorizontalForce:Number = 0, numVerticalForce:Number = 9.8, sleepBol:Boolean = true)
		{
			super();
			
			worldWidth = numWorldWidth;
			worldHeight = numWorldHeight;
			horizontalForce = numHorizontalForce;
			verticalForce = numVerticalForce;
			sleep = sleepBol;
			
			createWorld();
		}
		
		private function createWorld():void
		{
			var gravityForce:b2Vec2 = new b2Vec2(horizontalForce, verticalForce);
			
			var worldAABB:b2AABB = new b2AABB();
			worldAABB.upperBound.Set(worldWidth * 0.5, worldHeight * 0.5);
			worldAABB.lowerBound.Set(-(worldWidth * 0.5), -(worldHeight * 0.5));
			
			world = new b2World(worldAABB, gravityForce, sleep);
		}
		
		public function createBoundingWalls(numFriction:Number = 0.3, numRestitution:Number = 0.2):void
		{
			var floor:Box = new Box();
			floor.position(stage.stageWidth * 0.5, stage.stageHeight);
			floor.scale(stage.stageWidth, 10);
			floor.friction = numFriction;
			floor.restitution = numRestitution;
			floor.type = "static";
			addBody(floor);
			
			var leftWall:Box = new Box();
			leftWall.scale(10, stage.stageHeight);
			leftWall.position(0, stage.stageHeight * 0.5);
			leftWall.friction = numFriction;
			leftWall.restitution = numRestitution;
			leftWall.type = "static";
			addBody(leftWall);
			
			var rightWall:Box = new Box();
			rightWall.scale(10, stage.stageHeight);
			rightWall.position(stage.stageWidth, stage.stageHeight * 0.5);
			rightWall.friction = numFriction;
			rightWall.restitution = numRestitution;
			rightWall.type = "static";
			addBody(rightWall);
		}
		
		public function set showDebug(show:Boolean):void
		{
			if(show){
				var drawSprite:Sprite = new Sprite();
				physicsContainer.addChild(drawSprite);
				
				var debugDraw:b2DebugDraw = new b2DebugDraw();
				debugDraw.m_sprite = drawSprite;
				debugDraw.m_drawScale = AbstractView.SCALE;
				debugDraw.m_fillAlpha = 0.75;
				debugDraw.m_lineThickness = 1;
				debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
				
				world.SetDebugDraw(debugDraw);
			}
		}
		
		public function set allowDragging(value:Boolean):void
		{
			if(value){
				DragManager.initialize(stage, world)
			}else{
				DragManager.clear();
			}
		}
		
		public function addBody(bodyShape:AbstractObject, setMassFromShape:Boolean = true):b2Body
		{
			var tempBody:b2Body = world.CreateBody(bodyShape.bodyDef);
			bodyShape.body = tempBody;
			if(bodyShape is Box || bodyShape is OrientedBox){
				tempBody.CreateShape(bodyShape.polyDef);
			}else if(bodyShape is Circle){
				tempBody.CreateShape(bodyShape.circleDef);
			}
			if(bodyShape.bodyDef.userData is DisplayObject) addChild(bodyShape.bodyDef.userData);
			if(setMassFromShape) tempBody.SetMassFromShapes();
			return tempBody;
		}
		
		public function addJoint(joint:Joint):b2Joint
		{
			var tempJoint:b2Joint = world.CreateJoint(joint.jointDef);
			joint.joint = tempJoint;
			return tempJoint;
		}
	}
}